﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Architecture.BusinessLayer;
using CommonComponents.Configuration;
using CommonComponents.ExceptionHandling;
using LASLogic.BusinessLayer.DataModel;
using LASLogic.BusinessLayer.Requestor;
using LASLogic.BusinessLayer.Utilities;
using LASLogic.DataLayer.Implementor;

namespace LASLogic.BusinessLayer.BusinessLogic
{
    /// <summary>
    /// Clase que maneja la funcionalidad financiera del sistema
    /// </summary>
    public class FinancialManager : BusinessOrchestrator
    {

        #region Public Methods
        /// <summary>
        /// Metodo que permite añadir un nuevo asiento en el sistema
        /// </summary>
        /// <param name="entry">Asiento por añadir en el sistema</param>
        /// <returns>Booleano indicando el estado de la inserción</returns>
        public bool InsertEntry(Entry entry)
        {
            try
            {
                AppConfigReader appConfig = AppConfigReader.GetInstance();

                var insertionResult = EntryRequestor.GetInstance().InsertEntry(entry);
                if (!insertionResult) return false;

                var debitAccounts = entry.DebitAccounts;
                var creditAccounts = entry.CreditAccounts;

                // ciclo para añadir cuentas de debito
                foreach (var account in creditAccounts)
                {
                    EntryRequestor.GetInstance().AddAccountToEntry(account, appConfig.GetProperty(Constants.CREDIT_NAME));
                }

                // ciclo para añadir cuentas de credito
                foreach (var account in debitAccounts)
                {
                    EntryRequestor.GetInstance().AddAccountToEntry(account, appConfig.GetProperty(Constants.DEBIT_NAME));
                }

                return true;
            }
            catch (Exception ex)
            {
                ExceptionHandlingManager.ManageException(ex, ExceptionHandlingManager.ExceptionPolicyType.BusinessLayer);
                return false;
            }
        }


        /// <summary>
        /// Permite borrar un asiento de la base de datos generando un contra asiento al asiento especificado
        /// </summary>
        /// <param name="entryId">Identificador del asiento a borrar</param>
        /// <returns>Estado del borrado del asiento</returns>
        public bool EraseEntry(int entryId)
        {
            try
            {
                return EntryRequestor.GetInstance().EraseEntry(entryId);
            }
            catch (Exception ex)
            {
                ExceptionHandlingManager.ManageException(ex, ExceptionHandlingManager.ExceptionPolicyType.BusinessLayer);
                return false;
            }

        }

        /// <summary>
        /// Metodo que permite añadir una nueva cuenta al sistema
        /// </summary>
        /// <param name="account">Cuenta que se ingresará en el sistema</param>
        /// <returns>Booleano indicando el estado de la inserción</returns>
        public bool InsertNewAccount(Account account)
        {
            try
            {
                return AccountRequestor.GetInstance().InsertNewAccount(account);
            }
            catch (Exception ex)
            {
                ExceptionHandlingManager.ManageException(ex, ExceptionHandlingManager.ExceptionPolicyType.BusinessLayer);
                return false;
            }

        }

        /// <summary>
        /// Metodo que permite cambiar el estado de una cuenta
        /// </summary>
        /// <param name="accountId">Id de la cuenta</param>
        /// <param name="status">Nuevo estado de la cuenta</param>
        public bool ChangeAccountStatus(int accountId, string status)
        {
            try
            {
                return AccountRequestor.GetInstance().ChangeAccountStatus(accountId, status);
            }
            catch (Exception ex)
            {
                ExceptionHandlingManager.ManageException(ex, ExceptionHandlingManager.ExceptionPolicyType.BusinessLayer);
                return false;
            }
        }

        /// <summary>
        /// Permite borrar una cuenta del catálogo de cuentas
        /// </summary>
        /// <param name="accountId">Identificador de la cuenta a borrar</param>
        /// <returns>Booleano indicando el estado del borrado</returns>
        public bool EraseAccount(int accountId)
        {
            try
            {
                return AccountRequestor.GetInstance().EraseAccount(accountId);
            }
            catch (Exception ex)
            {
                ExceptionHandlingManager.ManageException(ex, ExceptionHandlingManager.ExceptionPolicyType.BusinessLayer);
                return false;
            }
        }


        /// <summary>
        /// Permite obtener el catalogo de cuentas de la base de datos
        /// </summary>
        /// <param name="companyId">Identificador de la compañia</param>
        /// <returns>Catalogo de cuentas de una compañia</returns>
        public AccountCatalog GetAccountingCatalog(int companyId)
        {
            try
            {
                return AccountRequestor.GetInstance().GetAccountingCatalog(companyId);
            }
            catch (Exception ex)
            {
                ExceptionHandlingManager.ManageException(ex, ExceptionHandlingManager.ExceptionPolicyType.BusinessLayer);
                return null;
            }
        }

        /// <summary>
        /// Permite insertar el catalogo de cuentas de una compañia
        /// </summary>
        /// <param name="companyId">Identificador de la compañia la cual se quiere insertar el catálogo</param>
        /// <returns>El id del catalogo contable</returns>
        public int InsertAccountingCatalog(int companyId)
        {
            try
            {
                return AccountRequestor.GetInstance().InsertAccountingCatalog(companyId);
            }
            catch (Exception ex)
            {
                ExceptionHandlingManager.ManageException(ex, ExceptionHandlingManager.ExceptionPolicyType.BusinessLayer);
                return -1;
            }
        }


        /// <summary>
        /// Metodo que permite insertar un periodo contabl
        /// </summary>
        /// <param name="companyId">Identificador de la compañia</param>
        /// <param name="accountingPeriod">Periodo a insertar</param>
        public bool InsertAccountingPeriod(int companyId, AccountingPeriod accountingPeriod)
        {
            try
            {
                return AccountRequestor.GetInstance().InsertAccountingPeriod(companyId, accountingPeriod);
            }
            catch (Exception ex)
            {
                ExceptionHandlingManager.ManageException(ex, ExceptionHandlingManager.ExceptionPolicyType.BusinessLayer);
                return false;
            }
        }

        /// <summary>
        /// Permite insertar un nuevo período de tiempo para una tasa de cambio
        /// </summary>
        /// <param name="companyId">Identificador de la compañia la cual se quiere insertar el catálogo</param>
        /// <param name="currencyIdDestiny">Identificador de la moneda correspondiente a la tasa de cambio</param>
        /// <param name="startDate">Fecha inicial en la que estará vigente el tipo de cambio</param>
        /// <param name="finishDate">Fecha final en la que estará vigente el tipo de cambio</param>
        /// <param name="exchangeRate">Valor del tipo de cambio</param>
        /// <param name="currencyIdBegining"></param>
        /// <returns>El id del catalogo contable</returns>
        public bool InsertExchangeRate(int companyId, int currencyIdBegining, int currencyIdDestiny, DateTime startDate, DateTime finishDate,
                                      decimal exchangeRate)
        {
            try
            {
                return AccountRequestor.GetInstance().InsertExchangeRate(companyId, currencyIdBegining, currencyIdDestiny, startDate, finishDate, exchangeRate);
            }
            catch (Exception ex)
            {
                ExceptionHandlingManager.ManageException(ex, ExceptionHandlingManager.ExceptionPolicyType.BusinessLayer);
                return false;
            }
        }

        /// <summary>
        /// Permite obtener los estados para un pais
        /// </summary>
        /// <param name="companyId">Identificador de la compania</param>
        /// <param name="currencyIdBegining">Nombre de la moneda que se quiere obtener el tipo de cambio</param>
        /// <param name="currencyIdDestiny">Nombre de la moneda destino que se quiere obtener el tipo de cambio</param>
        /// <param name="fechaActual">Fecha que se quiere averiguar el tipo de cambio de las monedas</param>
        /// <returns>Retorna una lista de estados</returns>
        public decimal GetExchangeRate(int companyId, int currencyIdBegining, int currencyIdDestiny, DateTime fechaActual)
        {
            try
            {
                return AccountRequestor.GetInstance().GetExchangeRate(companyId, currencyIdBegining, currencyIdDestiny,
                                                                      fechaActual);
            }
            catch (Exception ex)
            {
                ExceptionHandlingManager.ManageException(ex, ExceptionHandlingManager.ExceptionPolicyType.BusinessLayer);
                return 1;
            }
        }


        /// <summary>
        /// Permite obtener todas las monedas de la base de datos
        /// </summary>
        /// <returns>Lista de monedas de la base de datos</returns>
        public List<Currency> GetCurrencies()
        {
            try
            {
                return AccountRequestor.GetInstance().GetCurrencies();
            }
            catch (Exception ex)
            {
                ExceptionHandlingManager.ManageException(ex, ExceptionHandlingManager.ExceptionPolicyType.BusinessLayer);
                return null;
            }
        }

        /// <summary>
        /// Permite insertar una nueva moneda
        /// </summary>
        /// <param name="currency">Moneda a insertar</param>
        /// <returns>Si se logró efectuar correctamente</returns>
        public bool InsertCurrency(Currency currency)
        {
            try
            {
                return AccountRequestor.GetInstance().InsertCurrency(currency);
            }
            catch (Exception ex)
            {
                ExceptionHandlingManager.ManageException(ex, ExceptionHandlingManager.ExceptionPolicyType.BusinessLayer);
                return false;
            }
        }

        /// <summary>
        /// Permite cambiar la moneda a una cuenta
        /// </summary>
        /// <param name="accountId">identificador de la cuenta</param>
        /// <param name="currencyName">nombre de la moneda</param>
        /// <returns>Booleano si se cambia la moneda</returns>
        public bool ChangeAccountCurrency(int accountId, string currencyName)
        {
            try
            {
                return AccountRequestor.GetInstance().ChangeAccountCurrency(accountId, currencyName);
            }
            catch (Exception ex)
            {
                ExceptionHandlingManager.ManageException(ex, ExceptionHandlingManager.ExceptionPolicyType.BusinessLayer);
                return false;
            }
        }

        /// <summary>
        /// Permite cambiar la información de una cuenta
        /// </summary>
        /// <param name="account">Cuenta a ser modificada</param>
        /// <returns>Booleano si se cambia la moneda</returns>
        public bool ChangeAccountInformation(Account account)
        {
            try
            {
                return AccountRequestor.GetInstance().ChangeAccountInformation(account);
            }
            catch (Exception ex)
            {
                ExceptionHandlingManager.ManageException(ex, ExceptionHandlingManager.ExceptionPolicyType.BusinessLayer);
                return false;
            }
        }



        /// <summary>
        /// Permite obtener todos los asientos de una compañia en particular y acotado por fechas
        /// </summary>
        /// <param name="companyId">Identificador de una compañia</param>
        /// <param name="startDate">Fecha que marca el inicio de donde se quieren traer asientos</param>
        /// <param name="endDate">Fecha que marca el final de donde se quieren traer fechas</param>
        /// <returns>Obtiene todos los asientos de una compañia</returns>
        public List<Entry> GetEntriesFromCompany(int companyId, DateTime startDate, DateTime endDate)
        {
            try
            {
                return EntryRequestor.GetInstance().GetEntriesFromCompany(companyId, startDate, endDate);
            }
            catch (Exception ex)
            {
                ExceptionHandlingManager.ManageException(ex, ExceptionHandlingManager.ExceptionPolicyType.BusinessLayer);
                return null;
            }
        }




        #endregion

        #region Singleton

        /// <summary>
        /// Constructor de la clase FinancialManager
        /// </summary>
        private FinancialManager()
        {
        }

        /// <summary>
        /// Única instancia de esta clase
        /// </summary>
        private static FinancialManager _instance;

        /// <summary>
        /// Método para implementar el patrón de Singleton
        /// </summary>
        /// <returns>Instancia única de la clase</returns>
        public static FinancialManager GetInstance()
        {
            if (_instance == null)
                _instance = new FinancialManager();
            return _instance;
        }

        #endregion

    }
}
